//
//  Defines.h
//  LILTools
//
//  Created by xl on 2023/11/4.
//

#ifndef Defines_h
#define Defines_h

/// 如果是空对象或nil返回YES，否则返回NO。
/// @discussion @""、@[]、@{}、数字0以及任何 length 或 count 为0的都属于空对象。
FOUNDATION_STATIC_INLINE BOOL LILIsEmptyObject(id object) {
    if (!object || object == NSNull.null) return YES;
    if (([object respondsToSelector:@selector(length)] && [(NSData *)object length] > 0) ||
        ([object respondsToSelector:@selector(count)] && [(NSArray *)object count] > 0) ||
        ([object respondsToSelector:@selector(floatValue)] && [(id)object floatValue] != 0.0)) {
        return NO;
    }
    return YES;
}


/// 如果不是空对象返回YES，否则返回NO。
/// @discussion @""、@[]、@{}、数字0以及任何 length 或 count 为0的都属于空对象。
FOUNDATION_STATIC_INLINE BOOL LILIsNotEmptyObject(id object) {
    return !LILIsEmptyObject(object);
}


/// 返回一个包含起始值和终点值的随机整数。
/// @discussion begin 必须小于 end，否则返回begin。
FOUNDATION_STATIC_INLINE NSInteger LILRandomInteger(NSInteger begin, NSInteger end) {
    if (begin >= end) return begin;
    return ((NSInteger)(begin + (arc4random() % (end - begin + 1))));
}

/// 返回一个包含起始值和终点值的随机浮点数。
/// @discussion begin 必须小于 end，否则返回begin。
FOUNDATION_STATIC_INLINE double LILRandomFloat(NSInteger begin, NSInteger end) {
    if (begin >= end) return begin;
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        srand48(time(0));
    });
    
    NSInteger random = LILRandomInteger(begin, end-1);
    return random + drand48();
}


typedef void(^LILDelayedBlockHandle)(BOOL isCancel);

/// 将 LILCancel_dispatch_after 的任务标记为已取消，并在合适的时机释放它
/// @param delayedHandle 需要取消的任务
__attribute__((unused)) static void LILCancel_dispatch_after(LILDelayedBlockHandle delayedHandle) {
    if (delayedHandle == nil) return;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        delayedHandle(YES);
    });
}


/// dispatch_after 的可取消版本
///
/// @discussion 请使用 LILCancel_dispatch_after 函数在倒计时结束前取消它
///
/// @note block将会在主线程执行。
///
/// @code
///
/// LILDelayedBlockHandle handle = LILDispatch_after(2.0, ^{
///
///     ...
///
/// });
///
/// LILCancel_dispatch_after(handle);
/// @endcode
__attribute__((unused)) static LILDelayedBlockHandle LILDispatch_after(NSTimeInterval seconds, dispatch_block_t block) {
    if (block == nil) return nil;
    
    __block dispatch_block_t blockToExecute = [block copy];
    __block LILDelayedBlockHandle delayHandleCopy = nil;
    
    LILDelayedBlockHandle delayHandle = ^(BOOL isCancel) {
        if (!isCancel && blockToExecute) {
            blockToExecute();
        }
        
        blockToExecute = nil;
        delayHandleCopy = nil;
    };
    
    delayHandleCopy = [delayHandle copy];
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(seconds * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        !delayHandleCopy ?: delayHandleCopy(NO);
    });
    
    return delayHandleCopy;
}

#import <objc/runtime.h>
/// 获取实例方法列表。
void getInstanceMethodList(Class aClass, void(^block)(Method method, NSString *name)) {
    unsigned int count = 0;
    Method *instance_methods = class_copyMethodList(aClass, &count);
    
    for (int i = 0; i < count; i++) {
        Method method = instance_methods[i];
        SEL sel = method_getName(method);
        NSString *name = NSStringFromSelector(sel);
        !block ?: block(method, name);
    }
    
    free(instance_methods);
}

/// 获取类方法列表。
void getClassMethodList(Class aClass, void(^block)(Method method, NSString *name)) {
    getInstanceMethodList(object_getClass(aClass), block);
}


/// 获取实例成员变量列表。
void getInstanceIvarsList(Class aClass, void(^block)(Ivar ivar, NSString *name)) {
    unsigned int count = 0;
    Ivar *instance_ivars = class_copyIvarList(aClass, &count);
    
    for (int i = 0; i < count; i++) {
        Ivar ivar = instance_ivars[i];
        const char *cName = ivar_getName(ivar);
        NSString *name = [[NSString alloc] initWithUTF8String:cName];
        !block ?: block(ivar, name);
    }
    
    free(instance_ivars);
}

/// 获取类成员变量列表。
void getClassIvarsList(Class aClass, void(^block)(Ivar ivar, NSString *name)) {
    getInstanceIvarsList(object_getClass(aClass), block);
}

/// 获取实例属性列表。
void getInstancePropertyList(Class aClass, void(^block)(objc_property_t property, NSString *name)) {
    unsigned int count = 0;
    objc_property_t *instance_propertys = class_copyPropertyList(aClass, &count);
    
    for (int i = 0; i < count; i++) {
        objc_property_t property = instance_propertys[i];
        const char *cName = property_getName(property);
        NSString *name = [[NSString alloc] initWithUTF8String:cName];
        !block ?: block(property, name);
    }
    
    free(instance_propertys);
}

/// 获取类属性列表。
void getClassPropertyList(Class aClass, void(^block)(objc_property_t property, NSString *name)) {
    getInstancePropertyList(object_getClass(aClass), block);
}

/// 获取实例协议列表。
void getInstanceProtocolList(Class aClass, void(^block)(Protocol *protocol, NSString *name)) {
    unsigned int count = 0;
    __unsafe_unretained Protocol **instance_protocols = class_copyProtocolList(aClass, &count);
    
    for (int i = 0; i < count; i++) {
        Protocol *protocol = instance_protocols[i];
        const char *cName = protocol_getName(protocol);
        NSString *name = [[NSString alloc] initWithUTF8String:cName];
        !block ?: block(protocol, name);
    }
    
    free(instance_protocols);
}

/// 获取类协议列表。
void getClassProtocolList(Class aClass, void(^block)(Protocol *protocol, NSString *name)) {
    getInstanceProtocolList(object_getClass(aClass), block);
}

#import <dlfcn.h>
#import <mach-o/ldsyms.h>
/// 获取项目中所有的类(不包含系统类)。
NSArray<NSString *> * getProjectAllClassName1(void) {
    unsigned count;
    Dl_info info;
    
    dladdr(&_mh_execute_header, &info);
    const char **classes = objc_copyClassNamesForImage(info.dli_fname, &count);
    
    NSMutableArray *array = [NSMutableArray array];
    
    for (int i = 0; i < count; i++) {
        NSString *className = [NSString stringWithCString:classes[i] encoding:NSUTF8StringEncoding];
        [array addObject:className];
    }
    
    free(classes);
    
    return array;
}

/// 获取项目中所有的类(包含系统类)。
NSArray<NSString *> *getProjectAllClassName2(void) {
    int count = objc_getClassList(NULL, 0);
    if (count <= 0) return @[];
    
    Class *classes = NULL;
    classes = (__unsafe_unretained Class *)malloc(sizeof(Class) *count);
    count = objc_getClassList(classes, count);
    
    NSMutableArray *array = [NSMutableArray array];
    
    for (int i = 0; i < count; i++) {
        NSString *className = NSStringFromClass(classes[i]);
        [array addObject:className];
    }
    
    free(classes);
    
    return array;
}


#pragma mark - Macro
#ifndef LILRCodeSync
/// 使用同步方式执行一段异步代码并返回一个对象。
/// @code
/// LILRCodeSync(UIApplication.sharedApplication.delegate);
/// @endcode
#define LILRCodeSync(x) ({\
    id __block temp;\
    if ([NSThread isMainThread]) {\
        temp = x;\
    } else {\
        dispatch_semaphore_t signal = dispatch_semaphore_create(0);\
        dispatch_async(dispatch_get_main_queue(), ^{\
            temp = x;\
            dispatch_semaphore_signal(signal);\
        });\
        dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);\
    }\
    temp;\
})

#endif


#ifndef LILCodeSync


/// 使用同步方式执行一段异步代码。
/// @code
/// LILcodeSync(UIApplication.sharedApplication.delegate);
/// @endcode
#define LILCodeSync(x) ({\
    if ([NSThread isMainThread]) {\
        x;\
    } else {\
        dispatch_semaphore_t signal = dispatch_semaphore_create(0);\
        dispatch_async(dispatch_get_main_queue(), ^{\
            x;\
            dispatch_semaphore_signal(signal);\
        });\
        dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);\
    }\
})

#endif


/// 异步主线程执行，不强持有Self
#define LILDispatchAsyncOnMainQueue(x) \
{\
    __weak typeof(self) weakSelf = self;\
    dispatch_async(dispatch_get_main_queue(), ^{\
        typeof(weakSelf) self = weakSelf;\
        x;\
    });\
}


/// 异步子线程执行，不强持有Self
#define LILDispatchAsyncOnOtherQueue(x)\
{\
    __weak typeof(self) weakSelf = self;\
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{\
        typeof(weakSelf) self = weakSelf;\
        x;\
    });\
}

#endif /* Defines_h */
